﻿using System;

namespace Simp.CodeModel.CoreFunctions
{
	/// <summary>Encapsulates a function computing the power of a number.</summary>
	public class PowerFunction : IFunction, IFunctionSerializer
	{
		private static readonly string[] PARAMETER_NAMES = new[] { "a", "b" };

		#region IFunction Members
		string IFunction.FunctionName
		{
			get { return "Power"; }
		}

		string[] IFunction.ParameterNames
		{
			get { return PARAMETER_NAMES; }
		}

		IFunctionParameterBinding[] IFunction.DefaultParameterValues
		{
			get { return FunctionHelper.EmptyBindings; }
		}

		IFunction IFunction.Simplify(SimplificationMode simplificationMode, params IFunction[] parameters)
		{
			INumericFunction a = parameters[0] as INumericFunction;
			INumericFunction b = parameters[1] as INumericFunction;
			IntegerFunction bInteger = b.GetInteger();

			if (bInteger == null || bInteger.Value < 0)
			{
				RealFunction aReal = a.GetReal(simplificationMode == SimplificationMode.AllowApproximation);
				RealFunction bReal = b.GetReal(simplificationMode == SimplificationMode.AllowApproximation);

				if (aReal == null || bReal == null)
				{
					return null;
				}
				else
				{
					return new RealFunction(Math.Pow(aReal.Value, bReal.Value));
				}
			}
			else if (bInteger.Value == 0)
			{
				return new IntegerFunction(1);
			}
			else
			{	//	Recursively create a product
				IFunction function = parameters[0];

				for (int i = 0; i != bInteger.Value - 1; ++i)
				{
					function = new BoundFunctionCalling(new MultiplicationFunction(), function, parameters[0]);
				}

				return FunctionHelper.ApplySimplification(simplificationMode, function);
			}
		}

		IFunction IFunction.AcceptVisitor(IFunctionVisitor visitor)
		{
			return null;
		}
		#endregion

		#region IFunctionSerializer Members
		void IFunctionSerializer.Serialize(AppendOnlyStringBuilder builder, params IFunction[] parameters)
		{
			FunctionHelper.ValidateParameters(this, parameters);

			builder.Append("(");
			FunctionHelper.Serialize(parameters[0], builder);
			builder.Append(" ^ ");
			FunctionHelper.Serialize(parameters[1], builder);
			builder.Append(")");
		}
		#endregion
	}
}